/**
 * 允许转换的视口单位
 */
type IUnit = 'vw' | 'vmin' | 'vmax';

/**
 * 参数配置
 */
interface IOptions {
  /**
   * 设计稿宽度
   * @default 750
   */
  viewportWidth: number;
  /**
   * 转换后的视口单位
   * @default "vw"
   */
  viewportUnit: IUnit;
  /**
   * 转换后的字体视口单位
   * @default "vw"
   */
  fontViewportUnit: IUnit;
  /**
   * 单位精度
   * @default 10
   */
  unitPrecision: number;
}

interface IDecl {
  /**
   * 属性名称
   */
  prop: string;
  /**
   * 属性的值
   */
  value: string;
}

interface IRule {
  /**
   * 媒体查询参数
   */
  params: string;
}

const rpxRegex = /"[^"]+"|'[^']+'|url\([^\)]+\)|(\d*\.?\d+)rpx/g;

const defaultOptions: IOptions = {
  viewportWidth: 750,
  viewportUnit: 'vw',
  fontViewportUnit: 'vw',
  unitPrecision: 10,
};

function toFixed(number: number, precision: number): number {
  const multiplier = Math.pow(10, precision + 1);
  const wholeNumber = Math.floor(number * multiplier);
  return (Math.round(wholeNumber / 10) * 10) / multiplier;
}

function createRpxReplace(
  opts: IOptions,
  viewportUnit: IOptions['viewportUnit'],
  viewportSize: IOptions['viewportWidth'],
) {
  return function (m: string, $1: string) {
    if (!$1) return m;
    const pixels = parseFloat($1);
    const parsedVal = toFixed((pixels / viewportSize) * 100, opts.unitPrecision);
    return parsedVal + viewportUnit;
  };
}

function getUnit(prop: string, opts: IOptions) {
  return prop.indexOf('font') === -1 ? opts.viewportUnit : opts.fontViewportUnit;
}

function rpx2vw(options?: Partial<IOptions>) {
  const opts = Object.assign({}, defaultOptions, options);
  const { viewportWidth, viewportUnit } = opts;
  return {
    postcssPlugin: 'postcss-rpx2vw',
    Declaration(decl: IDecl) {
      const { prop, value } = decl;
      if (value.indexOf('rpx') === -1) return;
      const unit = getUnit(prop, opts);
      decl.value = value.replace(rpxRegex, createRpxReplace(opts, unit, viewportWidth));
    },
    AtRule: {
      media: (rule: IRule) => {
        const { params } = rule;
        if (params.indexOf('rpx') === -1) return;
        rule.params = params.replace(rpxRegex, createRpxReplace(opts, viewportUnit, viewportWidth));
      },
    },
  };
}

rpx2vw.postcss = true;

// 打包后需要将 exports.default=rpx2vw 替换为 module.exports=rpx2vw
export default rpx2vw;
